using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Reflection;
using System.Drawing;

// API collection, coded by marstone, not Microsoft
using Microsoft.Win32;
using System.Text;
using Studio.Windows;

namespace Studio.Game.GameBox
{
    /// <summary>
    /// Agent to Enable Game Controlling
    /// </summary>
    public class WindowSpy
    {

        protected IntPtr _Handle;
        /// <summary>
        /// Window Handle Attribute
        /// </summary>
        public IntPtr Handle
        {
            get { return _Handle; }
        }

        protected string _ClassName;
        /// <summary>
        /// ClassName Attribute
        /// </summary>
        public string ClassName
        {
            get { return _ClassName; }
        }

        private Rectangle _WindowRect;
        /// <summary>
        /// Top left conner coordinate & height, width of current found window
        /// </summary>
        public Rectangle WindowRect
        {
            get { return _WindowRect; }
        }

        protected string _WindowText;
        /// <summary>
        /// Window Text Attribute
        /// </summary>
        public string WindowText
        {
            get { return _WindowText; }        
        }

        /// <summary>
        /// dotNET does not support Colorful Cursor -_-!
        /// </summary>
        public static Cursor LoadCursorFromFile(string CursorFile)
        {
            Cursor cursor = new Cursor(Cursor.Current.Handle);
            // Call Win32 API
            IntPtr CursorHandle = WinAPI.LoadCursorFromFile(CursorFile);

            if (IntPtr.Zero != CursorHandle)
            {
                // The next sentense seems to be opaque... from csdn
                cursor.GetType().InvokeMember("handle", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
                       | BindingFlags.SetField, null, cursor, new object[] { CursorHandle });
                return cursor;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// Make a window highlighted.
        /// </summary>
        private void DrawWindowFrame(IntPtr Handle)
        { 
            if(IntPtr.Zero != Handle)
            {
                // Get window rectangle
                RECT Rect;
                WinAPI.GetWindowRect(Handle, out Rect);
                _WindowRect = new Rectangle(Rect.top, Rect.left, Rect.right - Rect.left, Rect.bottom - Rect.top);
                // Create Graphics
                Graphics Graph = Graphics.FromHwnd(Handle);
                // Create a pen
                Pen RedPen = new Pen(Brushes.OrangeRed, 3.0f);
                // Draw the frame
                Graph.DrawRectangle(RedPen, 0, 0, _WindowRect.Width, _WindowRect.Height);
            }
        }

        /// <summary>
        /// Refresh a window to normal
        /// </summary>
        private void RedrawWindowFrame(IntPtr Handle)
        {
            if (IntPtr.Zero != Handle)
            {
                // Redraw self
                WinAPI.RedrawWindow(Handle, IntPtr.Zero, IntPtr.Zero,
                    Constants.RDW_ALLCHILDREN | Constants.RDW_INTERNALPAINT | Constants.RDW_INVALIDATE |
                    Constants.RDW_UPDATENOW | Constants.RDW_ERASE | Constants.RDW_ERASENOW | Constants.RDW_FRAME);
                // Refraw parent
                IntPtr Parent = WinAPI.GetParent(Handle);
                if (IntPtr.Zero != Parent)
                {
                    WinAPI.RedrawWindow(Parent, IntPtr.Zero, IntPtr.Zero,
                        Constants.RDW_ALLCHILDREN | Constants.RDW_INTERNALPAINT | Constants.RDW_VALIDATE |
                        Constants.RDW_UPDATENOW | Constants.RDW_ERASE | Constants.RDW_ERASENOW | Constants.RDW_FRAME);
                }
            }
        }

        /// <summary>
        /// Earse last window found.
        /// </summary>
        public void EarseLastWindow()
        {
            if (IntPtr.Zero != _Handle) RedrawWindowFrame(_Handle);
        }

        /// <summary>
        /// 
        /// </summary>
        public bool GetWindowInformationFromCursor()
        { 
            // Get new window handle
            IntPtr HandleNew = GetWindowFromCursor();
            // validate
            if (IntPtr.Zero == HandleNew)
                return false;
            // Draw & Earse if necessary
            if (_Handle != HandleNew)
            {
                EarseLastWindow();
                _Handle = HandleNew;
                // High light current frame 
                DrawWindowFrame(_Handle);
            }
            // Get other informations of the current window
            // 1.ClassName
            int BufferSize = 256;
            StringBuilder Builder = new StringBuilder(BufferSize);
            WinAPI.GetClassName(_Handle, Builder, 256);
            _ClassName = Builder.ToString();
            // 2.WindowText
            IntPtr Length = WinAPI.SendMessage(_Handle, Constants.WM_GETTEXTLENGTH, IntPtr.Zero, IntPtr.Zero);
            if (0 < (int)Length)
            {
                Builder = new StringBuilder((int)Length);
                WinAPI.SendMessage(_Handle, Constants.WM_GETTEXT, Length, Builder);
            }
            _WindowText = Builder.ToString();
            // All done
            return true;
        }

        /// <summary>
        /// Get real window handle from cursor
        /// </summary>
        private IntPtr GetWindowFromCursor()
        {
            // Get cursor position first
            Point CursorPos;
            WinAPI.GetCursorPos(out CursorPos);
            // Get top window form point
            IntPtr WinHandle = WinAPI.WindowFromPoint(CursorPos);
            // Assert
            if (IntPtr.Zero == WinHandle) return IntPtr.Zero;
            // Get window style
            int WindowStyle = WinAPI.GetWindowLong(WinHandle, Constants.GWL_STYLE);
            // Get Desktop
            IntPtr Desktop = WinAPI.GetDesktopWindow();
            // Get ParentWindow
            IntPtr Parent = WinAPI.GetParent(WinHandle);
            // Set to parent if necessary
            if (IntPtr.Zero != Parent && Desktop != Parent && 0 != (WindowStyle & Constants.WS_CHILD))
                WinHandle = Parent;
            // Coordinate Transform
            WinAPI.ScreenToClient(WinHandle, ref CursorPos);
            // Find real window inside
            while (true)
            {
                // Get Child Handle
                IntPtr Child = WinAPI.RealChildWindowFromPoint(WinHandle, CursorPos);
                // Valid ?
                if (IntPtr.Zero == Child || Child == WinHandle) break;
                // Try next level
                WinHandle = Child;
            }
            return WinHandle;
        }

        public static Point GetWindowLocation(IntPtr Handle)
        {
            RECT Rect;
            WinAPI.GetWindowRect(Handle, out Rect);
            return new Point(Rect.left, Rect.top);
        }
    }
}
